import shlex
import subprocess
from typing import Optional, Tuple, Dict

from src.utils.function import logger


# usage:
#   执行简单命令
#       result = execute_shell_simple("python --version")
#   执行命令并获取详细信息
#       code, stdout, stderr = execute_shell("python --version", timeout=10)


def execute_shell(
        command: str,
        cwd: Optional[str] = None,
        timeout: Optional[int] = None,
        shell: bool = False,
        env: Optional[Dict[str, str]] = None
) -> Tuple[int, str, str]:
    """
    执行shell命令并返回结果

    Args:
        command (str): 要执行的命令
        cwd (Optional[str]): 命令执行的目录，默认为None
        timeout (Optional[int]): 超时时间（秒），默认为None
        shell (bool): 是否通过shell执行，默认为False
        env (Optional[Dict[str, str]]): 环境变量，默认为None

    Returns:
        Tuple[int, str, str]: 包含返回码、标准输出和标准错误的元组

    Raises:
        subprocess.TimeoutExpired: 如果命令执行超时
        Exception: 其他执行错误
    """
    try:
        # 如果不通过shell执行且命令是字符串，则进行分割
        if not shell and isinstance(command, str):
            cmd = shlex.split(command)
        else:
            cmd = command

        # 执行命令
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            cwd=cwd,
            shell=shell,
            env=env,
            universal_newlines=True
        )

        # 等待命令执行完成
        stdout, stderr = process.communicate(timeout=timeout)

        return process.returncode, stdout, stderr

    except subprocess.TimeoutExpired as e:
        logger().error(f"命令 {command} 执行失败 {e}")
        return -1, "", f"命令执行超时 {timeout} 秒"
    except Exception as e:
        logger().error(f"命令 {command} 执行失败 {e}")
        return -1, "", str(e)


def execute_shell_simple(command: str) -> str:
    """
    简单执行shell命令并返回输出结果

    Args:
        command (str): 要执行的命令

    Returns:
        str: 命令的标准输出结果

    Raises:
        Exception: 执行错误或命令返回非零退出码
    """
    code, stdout, stderr = execute_shell(command)
    logger().info(f"命令 {command} 执行成功")
    if code != 0:
        logger().error(f"命令 {command} 执行失败 {code}: {stderr}")
    return stdout
